3 var mwLanguageCache
= {}, oldGetOuterHtml
, formatnumTests
, specialCharactersPageName
;
5 QUnit
.module( 'mediawiki.jqueryMsg', QUnit
.newMwEnvironment( {
7 this.orgMwLangauge
= mw
.language
;
8 mw
.language
= $.extend( true, {}, this.orgMwLangauge
);
9 oldGetOuterHtml
= $.fn
.getOuterHtml
;
10 $.fn
.getOuterHtml = function () {
11 var $div
= $( '<div>' ), html
;
12 $div
.append( $( this ).eq( 0 ).clone() );
19 // Messages that are reused in multiple tests
20 // They are also all part of regression tests based on actual extensions. The actual messages have the same key,
21 // but without jquerymsg-test-.
23 'jquerymsg-test-pagetriage-del-talk-page-notify-summary': 'Notifying author of deletion nomination for [[$1]]',
24 'jquerymsg-test-categorytree-collapse-bullet': '[<b>−</b>]',
25 'jquerymsg-test-wikieditor-toolbar-help-content-signature-result': '<a href=\'#\' title=\'{{#special:mypage}}\'>Username</a> (<a href=\'#\' title=\'{{#special:mytalk}}\'>talk</a>)'
28 specialCharactersPageName
= '"Who" wants to be a millionaire & live on \'Exotic Island\'?';
30 teardown: function () {
31 mw
.language
= this.orgMwLangauge
;
32 $.fn
.getOuterHtml
= oldGetOuterHtml
;
36 function getMwLanguage( langCode
, cb
) {
37 if ( mwLanguageCache
[langCode
] !== undefined ) {
38 mwLanguageCache
[langCode
].add( cb
);
41 mwLanguageCache
[langCode
] = $.Callbacks( 'once memory' );
42 mwLanguageCache
[langCode
].add( cb
);
44 url
: mw
.util
.wikiScript( 'load' ),
46 skin
: mw
.config
.get( 'skin' ),
48 debug
: mw
.config
.get( 'debug' ),
50 'mediawiki.language.data',
56 }).done( function () {
57 mwLanguageCache
[langCode
].fire( mw
.language
);
58 }).fail( function () {
59 mwLanguageCache
[langCode
].fire( false );
63 QUnit
.test( 'Replace', 9, function ( assert
) {
64 var parser
= mw
.jqueryMsg
.getMessageFunction();
66 mw
.messages
.set( 'simple', 'Foo $1 baz $2' );
68 assert
.equal( parser( 'simple' ), 'Foo $1 baz $2', 'Replacements with no substitutes' );
69 assert
.equal( parser( 'simple', 'bar' ), 'Foo bar baz $2', 'Replacements with less substitutes' );
70 assert
.equal( parser( 'simple', 'bar', 'quux' ), 'Foo bar baz quux', 'Replacements with all substitutes' );
72 mw
.messages
.set( 'plain-input', '<foo foo="foo">x$1y<</foo>z' );
75 parser( 'plain-input', 'bar' ),
76 '<foo foo="foo">xbary&lt;</foo>z',
77 'Input is not considered html'
80 mw
.messages
.set( 'plain-replace', 'Foo $1' );
83 parser( 'plain-replace', '<bar bar="bar">></bar>' ),
84 'Foo <bar bar="bar">&gt;</bar>',
85 'Replacement is not considered html'
88 mw
.messages
.set( 'object-replace', 'Foo $1' );
91 parser( 'object-replace', $( '<div class="bar">></div>' ) ),
92 'Foo <div class="bar">></div>',
93 'jQuery objects are preserved as raw html'
97 parser( 'object-replace', $( '<div class="bar">></div>' ).get( 0 ) ),
98 'Foo <div class="bar">></div>',
99 'HTMLElement objects are preserved as raw html'
103 parser( 'object-replace', $( '<div class="bar">></div>' ).toArray() ),
104 'Foo <div class="bar">></div>',
105 'HTMLElement[] arrays are preserved as raw html'
108 mw
.messages
.set( 'external-link-replace', 'Foo [$1 bar]' );
110 parser( 'external-link-replace', 'http://example.org/?x=y&z' ),
111 'Foo <a href="http://example.org/?x=y&z">bar</a>',
112 'Href is not double-escaped in wikilink function'
116 QUnit
.test( 'Plural', 3, function ( assert
) {
117 var parser
= mw
.jqueryMsg
.getMessageFunction();
119 mw
.messages
.set( 'plural-msg', 'Found $1 {{PLURAL:$1|item|items}}' );
120 assert
.equal( parser( 'plural-msg', 0 ), 'Found 0 items', 'Plural test for english with zero as count' );
121 assert
.equal( parser( 'plural-msg', 1 ), 'Found 1 item', 'Singular test for english' );
122 assert
.equal( parser( 'plural-msg', 2 ), 'Found 2 items', 'Plural test for english' );
125 QUnit
.test( 'Gender', 11, function ( assert
) {
126 // TODO: These tests should be for mw.msg once mw.msg integrated with mw.jqueryMsg
127 // TODO: English may not be the best language for these tests. Use a language like Arabic or Russian
129 parser
= mw
.jqueryMsg
.getMessageFunction();
131 // The values here are not significant,
132 // what matters is which of the values is choosen by the parser
133 mw
.messages
.set( 'gender-msg', '$1: {{GENDER:$2|blue|pink|green}}' );
135 user
.options
.set( 'gender', 'male' );
137 parser( 'gender-msg', 'Bob', 'male' ),
139 'Masculine from string "male"'
142 parser( 'gender-msg', 'Bob', user
),
144 'Masculine from mw.user object'
147 user
.options
.set( 'gender', 'unknown' );
149 parser( 'gender-msg', 'Foo', user
),
151 'Neutral from mw.user object' );
153 parser( 'gender-msg', 'Alice', 'female' ),
155 'Feminine from string "female"' );
157 parser( 'gender-msg', 'User' ),
159 'Neutral when no parameter given' );
161 parser( 'gender-msg', 'User', 'unknown' ),
163 'Neutral from string "unknown"'
166 mw
.messages
.set( 'gender-msg-one-form', '{{GENDER:$1|User}}: $2 {{PLURAL:$2|edit|edits}}' );
169 parser( 'gender-msg-one-form', 'male', 10 ),
171 'Gender neutral and plural form'
174 parser( 'gender-msg-one-form', 'female', 1 ),
176 'Gender neutral and singular form'
179 mw
.messages
.set( 'gender-msg-lowercase', '{{gender:$1|he|she}} is awesome' );
181 parser( 'gender-msg-lowercase', 'male' ),
186 parser( 'gender-msg-lowercase', 'female' ),
191 mw
.messages
.set( 'gender-msg-wrong', '{{gender}} test' );
193 parser( 'gender-msg-wrong', 'female' ),
195 'Invalid syntax should result in {{gender}} simply being stripped away'
199 QUnit
.test( 'Grammar', 2, function ( assert
) {
200 var parser
= mw
.jqueryMsg
.getMessageFunction();
202 // Assume the grammar form grammar_case_foo is not valid in any language
203 mw
.messages
.set( 'grammar-msg', 'Przeszukaj {{GRAMMAR:grammar_case_foo|{{SITENAME}}}}' );
204 assert
.equal( parser( 'grammar-msg' ), 'Przeszukaj ' + mw
.config
.get( 'wgSiteName' ), 'Grammar Test with sitename' );
206 mw
.messages
.set( 'grammar-msg-wrong-syntax', 'Przeszukaj {{GRAMMAR:grammar_case_xyz}}' );
207 assert
.equal( parser( 'grammar-msg-wrong-syntax' ), 'Przeszukaj ' , 'Grammar Test with wrong grammar template syntax' );
210 QUnit
.test( 'Match PHP parser', mw
.libs
.phpParserData
.tests
.length
, function ( assert
) {
211 mw
.messages
.set( mw
.libs
.phpParserData
.messages
);
212 $.each( mw
.libs
.phpParserData
.tests
, function ( i
, test
) {
214 getMwLanguage( test
.lang
, function ( langClass
) {
217 assert
.ok( false, 'Language "' + test
.lang
+ '" failed to load' );
220 mw
.config
.set( 'wgUserLanguage', test
.lang
) ;
221 var parser
= new mw
.jqueryMsg
.parser( { language
: langClass
} );
223 parser
.parse( test
.key
, test
.args
).html(),
231 QUnit
.test( 'Links', 6, function ( assert
) {
232 var parser
= mw
.jqueryMsg
.getMessageFunction(),
234 expectedDisambiguationsText
,
235 expectedMultipleBars
,
236 expectedSpecialCharacters
;
239 The below three are all identical to or based on real messages. For disambiguations-text,
240 the bold was removed because it is not yet implemented.
243 mw
.messages
.set( 'jquerymsg-test-statistics-users', '注册[[Special:ListUsers|用户]]' );
245 expectedListUsers
= '注册' + $( '<a>' ).attr( {
246 title
: 'Special:ListUsers',
247 href
: mw
.util
.wikiGetlink( 'Special:ListUsers' )
248 } ).text( '用户' ).getOuterHtml();
251 parser( 'jquerymsg-test-statistics-users' ),
256 expectedDisambiguationsText
= 'The following pages contain at least one link to a disambiguation page.\nThey may have to link to a more appropriate page instead.\nA page is treated as a disambiguation page if it uses a template that is linked from ' +
258 title
: 'MediaWiki:Disambiguationspage',
259 href
: mw
.util
.wikiGetlink( 'MediaWiki:Disambiguationspage' )
260 } ).text( 'MediaWiki:Disambiguationspage' ).getOuterHtml() + '.';
261 mw
.messages
.set( 'disambiguations-text', 'The following pages contain at least one link to a disambiguation page.\nThey may have to link to a more appropriate page instead.\nA page is treated as a disambiguation page if it uses a template that is linked from [[MediaWiki:Disambiguationspage]].' );
263 parser( 'disambiguations-text' ),
264 expectedDisambiguationsText
,
265 'Wikilink without pipe'
268 mw
.messages
.set( 'jquerymsg-test-version-entrypoints-index-php', '[https://www.mediawiki.org/wiki/Manual:index.php index.php]' );
270 parser( 'jquerymsg-test-version-entrypoints-index-php' ),
271 '<a href="https://www.mediawiki.org/wiki/Manual:index.php">index.php</a>',
275 // Pipe trick is not supported currently, but should not parse as text either.
276 mw
.messages
.set( 'pipe-trick', '[[Tampa, Florida|]]' );
278 parser( 'pipe-trick' ),
279 'pipe-trick: Parse error at position 0 in input: [[Tampa, Florida|]]',
280 'Pipe trick should return error string.'
283 expectedMultipleBars
= $( '<a>' ).attr( {
285 href
: mw
.util
.wikiGetlink( 'Main Page' )
286 } ).text( 'Main|Page' ).getOuterHtml();
287 mw
.messages
.set( 'multiple-bars', '[[Main Page|Main|Page]]' );
289 parser( 'multiple-bars' ),
290 expectedMultipleBars
,
294 expectedSpecialCharacters
= $( '<a>' ).attr( {
295 title
: specialCharactersPageName
,
296 href
: mw
.util
.wikiGetlink( specialCharactersPageName
)
297 } ).text( specialCharactersPageName
).getOuterHtml();
299 mw
.messages
.set( 'special-characters', '[[' + specialCharactersPageName
+ ']]' );
301 parser( 'special-characters' ),
302 expectedSpecialCharacters
,
307 // Output for format plain when calling main (mediawiki.js) API.
308 // We're testing here to ensure our monkey-patching of mw.Message.prototype.parser doesn't
311 // Some of the tests use mw.msg, while others have mw.message(...).plain(). These two
312 // syntaxes should have identical behavior.
313 QUnit
.test( 'Plain', 4, function ( assert
) {
315 mw
.message( 'jquerymsg-test-pagetriage-del-talk-page-notify-summary' ).plain(),
316 'Notifying author of deletion nomination for [[$1]]',
317 'Square brackets in plain with no parameters'
321 mw
.msg( 'jquerymsg-test-pagetriage-del-talk-page-notify-summary', specialCharactersPageName
),
322 'Notifying author of deletion nomination for [[' + specialCharactersPageName
+ ']]',
323 'Square brackets in plain with one parameter'
327 mw
.msg( 'jquerymsg-test-categorytree-collapse-bullet' ),
328 mw
.messages
.get( 'jquerymsg-test-categorytree-collapse-bullet' ),
329 'Message with single square brackets is not changed'
333 mw
.message( 'jquerymsg-test-wikieditor-toolbar-help-content-signature-result' ).plain(),
334 mw
.messages
.get( 'jquerymsg-test-wikieditor-toolbar-help-content-signature-result' ),
335 'HTML message with curly braces is not changed'
339 QUnit
.test( 'Int', 4, function ( assert
) {
340 var parser
= mw
.jqueryMsg
.getMessageFunction(),
341 newarticletextSource
= 'You have followed a link to a page that does not exist yet. To create the page, start typing in the box below (see the [[{{Int:Helppage}}|help page]] for more info). If you are here by mistake, click your browser\'s back button.',
342 expectedNewarticletext
;
344 mw
.messages
.set( 'helppage', 'Help:Contents' );
346 expectedNewarticletext
= 'You have followed a link to a page that does not exist yet. To create the page, start typing in the box below (see the ' +
348 title
: mw
.msg( 'helppage' ),
349 href
: mw
.util
.wikiGetlink( mw
.msg( 'helppage' ) )
350 } ).text( 'help page' ).getOuterHtml() + ' for more info). If you are here by mistake, click your browser\'s back button.';
352 mw
.messages
.set( 'newarticletext', newarticletextSource
);
355 parser( 'newarticletext' ),
356 expectedNewarticletext
,
357 'Link with nested message'
360 mw
.messages
.set( 'portal-url', 'Project:Community portal' );
361 mw
.messages
.set( 'see-portal-url', '{{Int:portal-url}} is an important community page.' );
363 parser( 'see-portal-url' ),
364 'Project:Community portal is an important community page.',
368 mw
.messages
.set( 'newarticletext-lowercase',
369 newarticletextSource
.replace( 'Int:Helppage', 'int:helppage' ) );
372 parser( 'newarticletext-lowercase' ),
373 expectedNewarticletext
,
374 'Link with nested message, lowercase include'
377 mw
.messages
.set( 'uses-missing-int', '{{int:doesnt-exist}}' );
380 parser( 'uses-missing-int' ),
382 'int: where nested message does not exist'
386 // Tests that getMessageFunction is used for non-plain messages with curly braces or
387 // square brackets, but not otherwise.
388 QUnit
.test( 'mw.msg()', 22, function ( assert
) {
389 var oldGMF
, outerCalled
, innerCalled
;
392 'curly-brace': '{{int:message}}',
393 'single-square-bracket': '[https://www.mediawiki.org/ MediaWiki]',
394 'double-square-bracket': '[[Some page]]',
395 'regular': 'Other message'
398 oldGMF
= mw
.jqueryMsg
.getMessageFunction
;
400 mw
.jqueryMsg
.getMessageFunction = function() {
407 function verifyGetMessageFunction( key
, format
, shouldCall
) {
411 message
= mw
.message( key
);
413 assert
.strictEqual( outerCalled
, shouldCall
, 'Outer function called for ' + key
);
414 assert
.strictEqual( innerCalled
, shouldCall
, 'Inner function called for ' + key
);
417 verifyGetMessageFunction( 'curly-brace', 'parse', true );
418 verifyGetMessageFunction( 'curly-brace', 'plain', false );
420 verifyGetMessageFunction( 'single-square-bracket', 'parse', true );
421 verifyGetMessageFunction( 'single-square-bracket', 'plain', false );
423 verifyGetMessageFunction( 'double-square-bracket', 'parse', true );
424 verifyGetMessageFunction( 'double-square-bracket', 'plain', false );
426 verifyGetMessageFunction( 'regular', 'parse', false );
427 verifyGetMessageFunction( 'regular', 'plain', false );
429 verifyGetMessageFunction( 'jquerymsg-test-pagetriage-del-talk-page-notify-summary', 'plain', false );
430 verifyGetMessageFunction( 'jquerymsg-test-categorytree-collapse-bullet', 'plain', false );
431 verifyGetMessageFunction( 'jquerymsg-test-wikieditor-toolbar-help-content-signature-result', 'plain', false );
433 mw
.jqueryMsg
.getMessageFunction
= oldGMF
;
439 number
: 987654321.654321,
440 result
: '987654321.654321',
441 description
: 'formatnum test for English, decimal seperator'
445 number
: 987654321.654321,
446 result
: '٩٨٧٦٥٤٣٢١٫٦٥٤٣٢١',
447 description
: 'formatnum test for Arabic, with decimal seperator'
451 number
: '٩٨٧٦٥٤٣٢١٫٦٥٤٣٢١',
454 description
: 'formatnum test for Arabic, with decimal seperator, reverse'
460 description
: 'formatnum test for Arabic, negative number'
467 description
: 'formatnum test for Arabic, negative number, reverse'
471 number
: 987654321.654321,
472 result
: '987654321,654321',
473 description
: 'formatnum test for Nederlands, decimal seperator'
479 description
: 'formatnum test for Nederlands, negative number'
483 number
: 'invalidnumber',
484 result
: 'invalidnumber',
485 description
: 'formatnum test for Nederlands, invalid number'
489 QUnit
.test( 'formatnum', formatnumTests
.length
, function ( assert
) {
490 mw
.messages
.set( 'formatnum-msg', '{{formatnum:$1}}' );
491 mw
.messages
.set( 'formatnum-msg-int', '{{formatnum:$1|R}}' );
492 $.each( formatnumTests
, function ( i
, test
) {
494 getMwLanguage( test
.lang
, function ( langClass
) {
497 assert
.ok( false, 'Language "' + test
.lang
+ '" failed to load' );
500 mw
.messages
.set(test
.message
);
501 mw
.config
.set( 'wgUserLanguage', test
.lang
) ;
502 var parser
= new mw
.jqueryMsg
.parser( { language
: langClass
} );
504 parser
.parse( test
.integer
? 'formatnum-msg-int' : 'formatnum-msg',
505 [ test
.number
] ).html(),
513 }( mediaWiki
, jQuery
) );